// VInst.cpp
// implement the VInst class

#include "crossbit/VInst.h"
#include <iostream>
#include <string>
#include <sstream>

using namespace crossbit;

namespace crossbit {

#define VINSTTEMPLATE(OPCODE, FORMATSTRING) \
	case OPCODE: format = FORMATSTRING; break;

		     std::ostream& operator<<(std::ostream& os, const VInst& inst)
		     {
			     Opcode op = inst.getOpcode();
			     std::string format;


			     switch(op) {

				     // VInstruction Template Definition:
				     // VINSTTEMPLATE(OPCODE, <format-string>), 
				     //   where <format-string> specifies how to print VInst to text-form
				     //   %r: register
				     //   %i: immediate
				     //   %d: data address
				     //   %p: program counter
				     //   %b: block size
				     //   %c: compare condition code
				     //   %w: plain word in hex
				     //
				     VINSTTEMPLATE(OP_GET,	    "GET  s%r, v%r")
					     VINSTTEMPLATE(OP_PUT,	    "PUT  v%r, s%r")
					     VINSTTEMPLATE(OP_LD,	    "LD   v%r(%i), %b, v%r")
					     VINSTTEMPLATE(OP_ST,	    "ST   v%r, %b, v%r(%i)")
					     VINSTTEMPLATE(OP_MOV,	    "MOV  v%r, v%r")
					     VINSTTEMPLATE(OP_LI,	    "LI   %i, v%r")
					     VINSTTEMPLATE(OP_ADD,	    "ADD  v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_SUB,	    "SUB  v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_AND,	    "AND  v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_OR,	    "OR   v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_XOR,	    "XOR  v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_NOT,	    "NOT  v%r, v%r")
					     VINSTTEMPLATE(OP_MUL,	    "MUL  v%r, v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_MULU,	    "MULU v%r, v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_DIV,	    "DIV  v%r, v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_DIVU,	    "DIVU v%r, v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_SLL,	    "SLL  v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_SLLV,	    "SLLV  v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_SRL,	    "SRL  v%r, %i, v%r")
					     VINSTTEMPLATE(OP_SRLV,	    "SRLV  v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_SRA,	    "SRA  v%r, %i, v%r")
					     VINSTTEMPLATE(OP_SRAV,	    "SRAV  v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_SEXT,	    "SEXT v%r, %b, v%r")
					     VINSTTEMPLATE(OP_ZEXT,	    "ZEXT v%r, %b, v%r")
					     VINSTTEMPLATE(OP_CMP,	    "CMP  %c, v%r, v%r, v%r")
					     VINSTTEMPLATE(OP_JMP,	    "JMP  v%r(%i)")
					     VINSTTEMPLATE(OP_BRANCH,    "BRANCH %c, v%r, v%r, v%r(%i)")
					     VINSTTEMPLATE(OP_HALT,	    "HALT")
					     VINSTTEMPLATE(OP_SYSCALL,   "SYSCALL")
					     VINSTTEMPLATE(OP_CALL,	    "CALL %w")
					     // float-point
					     VINSTTEMPLATE(OP_FGET_S,    "FGETS  f%r")
					     VINSTTEMPLATE(OP_FPUT_S,    "FPUTS  f%r")
					     VINSTTEMPLATE(OP_FGET_D,    "FGETD  f%r")
					     VINSTTEMPLATE(OP_FPUT_D,    "FPUTD  f%r")
					     VINSTTEMPLATE(OP_FLD,	    "FLD   v%r(%i), %b, f%r")
					     VINSTTEMPLATE(OP_FST,	    "FST   f%r, %b, v%r(%i)")
					     VINSTTEMPLATE(OP_FMOV,	    "FMOV  f%r, f%r")
					     VINSTTEMPLATE(OP_FADD_S,    "FADDS")
					     VINSTTEMPLATE(OP_FADD_D,    "FADDD")
					     VINSTTEMPLATE(OP_FSUB_S,    "FSUBS")
					     VINSTTEMPLATE(OP_FSUB_D,    "FSUBD")
					     VINSTTEMPLATE(OP_FMUL_S,    "FMULS")
					     VINSTTEMPLATE(OP_FMUL_D,    "FMULD")
					     VINSTTEMPLATE(OP_FDIV_S,    "FDIVS")
					     VINSTTEMPLATE(OP_FDIV_D,    "FDIVD")
					     VINSTTEMPLATE(OP_FNEG_S,    "FNEGS")
					     VINSTTEMPLATE(OP_FNEG_D,    "FNEGD")
					     VINSTTEMPLATE(OP_FABS_S,    "FABSS")
					     VINSTTEMPLATE(OP_FABS_D,    "FABSD")
					     VINSTTEMPLATE(OP_FSQRT_S,   "FSQRTS")
					     VINSTTEMPLATE(OP_FSQRT_D,   "FSQRTD")
					     VINSTTEMPLATE(OP_FCMP_S,    "FCMPS")
					     VINSTTEMPLATE(OP_FCMP_D,    "FCMPD")
					     VINSTTEMPLATE(OP_FCONV,	    "FCONV f%r, %b, f%r, %b")
			     }

			     std::string::size_type idx = 0;	// string index
			     XTInt32 nopr = 0;		// operand index
			     while ( (idx = format.find('%', idx)) != std::string::npos) {
				     XTUint8 f = format[idx + 1];
				     Operand opr = inst.getOperand(++nopr);
				     std::stringstream ss;

				     switch (f) {
					     case 'r':	// register
						     ss << (XTInt32)opr.reg;
						     break;
					     case 'i':	// immediate
						     ss << "0x" << std::hex << opr.imm;
						     break;
						     /*
							case 'd':	// data address
							ss << "(0x" << hex << opr.mem.disp << ')' << 'v' << dec << opr.mem.reg;
							break;
							case 'p':	// program counter
							ss << ((opr.pc.type == SPC) ? 'S' : 'T')
							<< "(0x" << hex << opr.pc.disp << ')' << 'v' << opr.pc.reg;
							break;
						      */
					     case 'c':	// condition code
						     switch (opr.cc) {
							     case EQ: ss << "EQ"; break;
							     case NE: ss << "NE"; break;
							     case GT: ss << "GT"; break;
							     case GE: ss << "GE"; break;
							     case LT: ss << "LT"; break;
							     case LE: ss << "LE"; break;
							     case AB: ss << "AB"; break;
							     case BE: ss << "BE"; break;
						     }
						     break;
					     case 'b':	// block size
						     switch (opr.size) {
							     case BYTE:	    ss << "BYTE"; break;
							     case HALFWORD:  ss << "HALFWORD"; break;
							     case WORD:	    ss << "WORD"; break;
							     case DWORD:	    ss << "DWORD"; break;
							     case FLOAT:	    ss << "FLOAT"; break;
							     case DOUBLE:    ss << "DOUBLE"; break;
						     }
						     break;
					     case 'w':	// plain word
						     ss << "0x" << std::hex << opr.word;
						     break;
					     default:
						     ;
				     }
				     format.replace(idx, 2, ss.str());
				     idx++;
			     }

			     return os << format;
		     }

}
